
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <future>
#include "common.h"
using namespace std;


// 多线程参数的三种传递方式，
// 获取Thread ID 对象:
//    std::this_thread::get_id()  thd1.get_id()
// std::ref(value) 获取value的引用
// std::move(value) 转移value的所有权，不需要拷贝，提高程序的运行效率
namespace THREAD_ARGV_TRANS_DAY28
{
    int value = 0;

    void handler_1(int i)
    {
        cout << "Thread " << i << " is created!" << endl;
        cout << "thd1 ID is: " << std::this_thread::get_id() << endl;
        for(int i = 0;i < 10000;i++)
        {
            value++;
        }
    }

    void handler_2(int & i)
    {
        cout << "Thread " << i << " is created!" << endl;
        for(int i = 0;i < 10000;i++)
        {
            value++;
        }
    }

    void handler_3(int && i)
    {
        cout << "Thread " << i << " is created!" << endl;
        
        for(int i = 0;i < 10000;i++)
        {
            value++;
        }
        
    }
};


namespace THREAD_END_DAY28
{
    int value = 0;
    void handler_1(int i)
    {
        cout << "Thread " << i << " is created!" << endl;
        for(int i = 0;i < 10000;i++)
        {
            value++;
        }

    }
};

namespace THREAD_MUTEX_DAY28
{
    std::mutex mtx;
    int value = 0;
    void handler_1()
    {
        mtx.lock();
        cout << "Thread is created!" << endl;
        for(int i = 0;i < 10000;i++)
        {
            value++;
        }
        mtx.unlock();
    }
};


namespace THREAD_LOCK_GUARD_DAY28
{
    int value = 0;
    std::mutex mtx;

    void safe_increment()
    {
        const std::lock_guard<std::mutex> lock(mtx);
        
        for (int i = 0;i < 10000;i++)
        {
            ++value;
        }
        
        std::cout << std::this_thread::get_id() << ": " << value << '\n';
        // mtx 自动解锁
    }   
};

namespace THREAD_UNIQUE_LOCK_DAY28
{
    struct Person {
        explicit Person(int num) : num_things{num} {}

        int num_things;
        std::mutex m;
    };

    void handler(Person &from, Person &to, int num)
    {
        // defer_lock表示暂时unlock，默认自动加锁
        std::unique_lock<std::mutex> lock1(from.m, std::defer_lock);
        std::unique_lock<std::mutex> lock2(to.m, std::defer_lock);

        //两个同时加锁
        std::lock(lock1, lock2);//或者使用lock1.lock()

        from.num_things -= num; // 90  95
        to.num_things += num;   // 60  55
        //作用域结束自动解锁,也可以使用lock1.unlock()手动解锁
    }
};

namespace THREAD_UNIQUE_LOCK1_DAY28
{
    using namespace std;
    mutex m;

    void handler1(int & a)
    {
        cout << "proc1 before!" << endl;
        unique_lock<mutex> g1(m, defer_lock);   //始化了一个没有加锁的mutex
        cout << "proc1 after!" << endl;
        
        g1.lock();  //手动加锁，注意，不是m.lock()
        cout << "proc1函数正在改写a" << endl;
        cout << "proc1函数a为" << a << endl;
        a = a+2;
        cout << "proc1函数a+2为" << a << endl;
        g1.unlock();    //临时解锁
        cout << "尝试自动解锁" << endl;
        g1.lock();
        cout << "运行后自动解锁" << endl;
    }   //自动解锁
    
    void handler2(int & a)
    {
        cout << "proc2 before!" << endl;
        unique_lock<mutex> g2(m, try_to_lock);  //尝试加锁，但如果没有锁定成功，会立即返回，不会阻塞在那里
        cout << "proc2函数正在改写a" << endl;
        cout << "proc2函数a为" << a << endl;
        a = a+1;
        cout << "proc2函数a+1为" << a << endl;
    }   //自动解锁
};


namespace THREAD_CONDITION_VARIABLE_DAY28
{
    std::mutex mtx; // 互斥锁
    std::condition_variable cv; // 条件变量
    bool ready = false; // 全局标志位

    void print_id(int id) {
        std::unique_lock<std::mutex> lck(mtx);
        while (!ready) { // 如果标志位为false，等待
            cv.wait(lck); // 释放锁并等待条件变量唤醒
        }
        // 打印线程ID
        std::cout << "thread " << id << ' ' << std::endl;
    }

    void go() {
        std::unique_lock<std::mutex> lck(mtx);
        ready = true; // 设置标志位为true
        cv.notify_all(); // 唤醒所有等待的线程
    }

};



namespace THREAD_CONDITION_VARIABLE1_DAY28
{
    std::condition_variable cv;

    int value;

    void read_value()
    {
        std::cin >> value;
        cv.notify_one();
    }

};



int main (int argc, char *argv[])
{


    {
        using namespace THREAD_ARGV_TRANS_DAY28;
        __LOG__("多线程参数传递--值传递-引用传递-移动语义");
        // 值传递
        int thID1 = 1;
        thread thd1 = thread(handler_1,thID1);

        // 引用传递
        int thID2 = 2;
        thread thd2 = thread(handler_2,std::ref(thID2));
        cout << "thd2 ID is: " << thd2.get_id() << endl; 

        // 移动语义
        int thID3 = 3;
        thread thd3 = thread(handler_3,std::move(thID3));
        cout << "thd3 ID is: " << thd3.get_id() << endl; 

        thd1.join();
        thd2.join();
        thd3.join();

        cout << "value: " << value << endl;
    }
    

    {
        using namespace THREAD_END_DAY28;
        {
            __LOG__("detach式");
            // 值传递
            int thID1 = 1;
            thread thd1 = thread(handler_1,thID1);
            cout << "thd1 ID is: " << thd1.get_id() << endl;
            thd1.detach();

            cout << "value: " << value << endl;
        }
        
    }
    

    {
        using namespace THREAD_END_DAY28;

        {
             __LOG__("join式");
            // 值传递
            int thID1 = 1;
            thread thd1 = thread(handler_1,thID1);
            cout << "thd1 ID is: " << thd1.get_id() << endl;
            thd1.join();

            cout << "value: " << value << endl;
        }
        
    }


    {
        using namespace THREAD_MUTEX_DAY28;
        __LOG__("Mutex");

        thread thd1 = thread(handler_1);
        cout << "thd1 ID is: " << thd1.get_id() << endl;

        thread thd2 = thread(handler_1);

        
        cout << "thd2 ID is: " << thd2.get_id() << endl; 

        thd1.join();
        thd2.join();

        
        cout << "value: " << value << endl;
    }

    {
        using namespace THREAD_LOCK_GUARD_DAY28;
        __LOG__("lock_guard");
        std::cout << "main id: " <<std::this_thread::get_id()<<std::endl;
        std::cout << "main: " << value << '\n';

        std::thread t1(safe_increment);
        std::thread t2(safe_increment);

        t1.join();
        t2.join();

        std::cout << "main: " << value << '\n';
    }

    {
        using namespace THREAD_UNIQUE_LOCK_DAY28;
        __LOG__("unique_lock");
        Person acc1(100);
        Person acc2(50);

        std::thread t1(handler, std::ref(acc1), std::ref(acc2), 10);
        std::thread t2(handler, std::ref(acc2), std::ref(acc1), 5);

        t1.join();
        t2.join();
        std::cout << "acc1 num_things: " << acc1.num_things << std::endl;
        std::cout << "acc2 num_things: " << acc2.num_things << std::endl;
    }

    {
        using namespace THREAD_UNIQUE_LOCK1_DAY28;
        __LOG__("unique_lock1");
        int a = 0;
        thread t1(handler1, ref(a));
        thread t2(handler2, ref(a));
        t1.join();
        t2.join();

        cout << "最后a: " << a << endl;
    }


    {
        using namespace THREAD_CONDITION_VARIABLE_DAY28;
        __LOG__("condition_variable_notify_all");

        std::thread threads[10];
        for (int i = 0; i < 10; ++i) {
            threads[i] = std::thread(print_id, i);
        }

        std::cout << "10 threads ready to race...";
        go(); // 通知所有线程开始比赛

        for (auto& th : threads) {
            th.join(); // 等待所有线程结束
        }
    }

    {
        using namespace THREAD_CONDITION_VARIABLE1_DAY28;
        __LOG__("condition_variable_notify_one");
        std::cout << "Please, enter an integer (I'll be printing dots): \n";
        std::thread th (read_value);

        std::mutex mtx;
        std::unique_lock<std::mutex> lck(mtx);
        while (cv.wait_for(lck,std::chrono::seconds(1))==std::cv_status::timeout) {
            std::cout << '.' << std::endl;
        }
        std::cout << "You entered: " << value << '\n';

        th.join();
    }

    {
        using namespace THREAD_CONDITION_VARIABLE1_DAY28;
        __LOG__("异步线程-future");

         // 创建一个异步任务，计算两个数的和
        std::future<int> result = std::async([]() {
            std::this_thread::sleep_for(std::chrono::seconds(2)); // 模拟耗时操作
            return 42 + 84;
        });

        // 在主线程中等待异步任务完成
        result.wait();

        // 获取异步任务的结果
        int sum = result.get();

        std::cout << "The sum is: " << sum << std::endl;
    }

    return 0;
}


